<?php

declare( strict_types = 1 );

namespace App\Common\Model\Base\DataUnit\DataOperate;

use App\Common as com;

/**
 * Trait DataOperate
 * @property array $_dataOperate_TableModel
 * @property com\Model\Base\DataUnit\DataOperate[] $_dataOperate_Data
 */
trait Traits {

	/**
	 * @var com\Model\Base\DataUnit\DataOperates
	 */
	private com\Model\Base\DataUnit\DataOperates $_datas;

	/**
	 * @var array|null
	 */
	private array|null $_dataOperate_Data_Runtime = null;

	/**
	 * 魔术方法->call
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return mixed
	 * @throws
	 */
	public function __call( string $name, array $args ) {
		return $this->_dataOperate_Call( $name, $args );
	}

	/**
	 * 魔术方法call处理
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @param mixed $notExistReturn 没有数据时返回 [null]抛出异常
	 * @return mixed|\Exception 返回数据(可能抛出的异常:[get*]com\Cla\Err\Code::$sysDataErrorSeverity。[其他]com\Cla\Err\Code::$sysFunExecuteError)
	 * @throws
	 */
	protected function _dataOperate_Call( string $name, array $args, mixed $notExistReturn = null ) {
		// 取动作类型
		$startSize = strpos( $name, '_' );
		$action = $startSize !== false ? substr( $name, 0, $startSize + 1 ) : '';
		// 处理where属性
		switch( $action ){
			case 'goData_':
				throw com\Lib\Err\Exception::makeOfNew( '已不支持goData用法，请更改为gowData或newData(' . $name . ')', com\Cla\Err\Code::$sysFunExecuteError );
			case 'gowData_':
				return $this->__magicCallOfDataOfGowData( $name, $args );
			case 'newData_':
				return $this->__magicCallOfDataOfNewData( $name, $args );
			case 'getData_':
				return $this->__magicCallOfDataOfGetData( $name, $args );
			case 'setData_':
				return $this->__magicCallOfDataOfSetData( $name, $args );
			case 'fieldData_':
				return $this->__magicCallOfDataOfFieldData( $name, $args );
			case 'whereData_':
				return $this->__magicCallOfDataOfWhereData( $name, $args );
			case 'orWhereData_':
				return $this->__magicCallOfDataOfOrWhereData( $name, $args );
			case 'whereEqData_':
				return $this->__magicCallOfDataOfWhereEqData( $name, $args );
			case 'pluckData_':
				return $this->__magicCallOfDataOfPluckData( $name, $args );
		}
		//
		if( $notExistReturn !== null ) return $notExistReturn;
		throw com\Lib\Err\Exception::makeOfNew( '魔术方法不存在：' . $name, com\Cla\Err\Code::$sysFunExecuteError );
	}

	/**
	 * call->gowData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return com\Model\Base\DataUnit\DataOperate 返回数据(如无法处理则抛出异常:com\Cla\Err\Code::$sysDataNotExist)
	 */
	private function __magicCallOfDataOfGowData( string $name, array $args ):com\Model\Base\DataUnit\DataOperate {
		// ...
		if( ! empty( $args ) ){
			throw com\Lib\Err\Exception::makeOfNew( $name . '不允许传入参数，请检查语法是否错误', com\Lib\Err\Code::$sysFunExecuteError );
		}
		// 取出属性名
		$propertyName = substr( $name, 7 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		// 检查可以读的属性
		if( ! array_key_exists( $propertyName, $this->_dataOperate_Data ?? [] ) ){
			throw com\Lib\Err\Exception::makeOfNew( '字段不存在，请检查：$this->_dataOperate_Data[\'' . $propertyName . '\']', com\Cla\Err\Code::$sysDataNotExist );
		}
		//
		return $this->_dataOperate( $propertyName );
	}

	/**
	 * call->newData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return com\Model\Base\DataUnit\DataOperate 返回数据(如无法处理则抛出异常:com\Cla\Err\Code::$sysDataNotExist)
	 * @throws
	 */
	private function __magicCallOfDataOfNewData( string $name, array $args ):com\Model\Base\DataUnit\DataOperate {
		// ...
		if( ! empty( $args ) ){
			throw com\Lib\Err\Exception::makeOfNew( $name . '不允许传入参数，请检查语法是否错误', com\Lib\Err\Code::$sysFunExecuteError );
		}
		// 取出属性名
		$propertyName = substr( $name, 7 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		// 检查可以读的属性
		if( ! array_key_exists( $propertyName, $this->_dataOperate_Data ?? [] ) ){
			throw com\Lib\Err\Exception::makeOfNew( '字段不存在，请检查：$this->_dataOperate_Data[\'' . $propertyName . '\']', com\Cla\Err\Code::$sysDataNotExist );
		}
		//
		return $this->_newDataOperate( $propertyName );
	}

	/**
	 * call->getData
	 * @param string $name 方法名
	 * @param array $args 参数。$args[0]默认值
	 * @return com\Model\Base\DataUnit\DataOperate 返回数据(如无法处理则抛出异常:com\Cla\Err\Code::$sysDataNotExist)
	 */
	private function __magicCallOfDataOfGetData( string $name, array $args ):com\Model\Base\DataUnit\DataOperate {
		// 取出属性名
		$propertyName = substr( $name, 8 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		//
		return $this->_dataOperate( $propertyName )->get( $args[0] ?? null );
	}

	/**
	 * call->setData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return static
	 * @throws
	 */
	private function __magicCallOfDataOfSetData( string $name, array $args ):static {
		// 取出属性名
		$propertyName = substr( $name, 8 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		//
		if( count( $args ) <= 0 ){
			throw com\Lib\Err\Exception::makeOfNew( '没有传入设置值', com\Lib\Err\Code::$sysFunParamError );
		}
		$this->_dataOperate( $propertyName )->set( $args[0] );
		//
		return $this;
	}

	/**
	 * call->fieldData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return static
	 */
	private function __magicCallOfDataOfFieldData( string $name, array $args ):static {
		// 取出属性名
		$propertyName = substr( $name, 10 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		//
		if( isset( $args[0] ) ){
			$this->_dataOperate( $propertyName )->addFieldAs( $args[0] );
		} else{
			$this->_dataOperate( $propertyName )->addField();
		}
		//
		return $this;
	}

	/**
	 * call->whereData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return static
	 * @throws
	 */
	private function __magicCallOfDataOfWhereData( string $name, array $args ):static {
		// 取出属性名
		$propertyName = substr( $name, 10 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		//
		if( count( $args ) === 0 ){
			throw com\Lib\Err\Exception::makeOfNew( '没有传入where参数', com\Lib\Err\Code::$sysFunParamError );
		}
		//
		//
		$this->_dataOperate( $propertyName )->where( ...$args );
		//
		return $this;
	}

	/**
	 * call->orWhereData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return static
	 * @throws
	 */
	private function __magicCallOfDataOfOrWhereData( string $name, array $args ):static {
		// 取出属性名
		$propertyName = substr( $name, 12 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		//
		if( count( $args ) === 0 ){
			throw com\Lib\Err\Exception::makeOfNew( '没有传入orWhere参数', com\Lib\Err\Code::$sysFunParamError );
		}
		//
		$this->_dataOperate( $propertyName )->orWhere( ...$args );
		//
		return $this;
	}

	/**
	 * call->whereEqData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return static
	 */
	private function __magicCallOfDataOfWhereEqData( string $name, array $args ):static {
		// 取出属性名
		$propertyName = substr( $name, 12 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		//
		$this->_dataOperate( $propertyName )->whereEq( $args[0] );
		//
		return $this;
	}

	/**
	 * call->pluckData
	 * @param string $name 方法名
	 * @param array $args 参数
	 * @return com\Lib\Utils\Helper\Array_
	 */
	private function __magicCallOfDataOfPluckData( string $name, array $args ):com\Lib\Utils\Helper\Array_ {
		// 取出属性名
		$propertyName = substr( $name, 10 );
		$propertyName = com\Lib\Fun\Str::parseName( $propertyName, 1, false );
		//
		return $this->_dataOperate( $propertyName )->pluck();
	}

	/**
	 * @param string $propertyName
	 * @param mixed $assignDefaultValue 指定的默认值。[null][默认]
	 * @param string|null $dataOperateClass 自定义类
	 * @return com\Model\Base\DataUnit\DataOperate
	 * @throws
	 */
	protected function _dataOperate( string $propertyName, mixed $assignDefaultValue = null, string|null $dataOperateClass = null ):com\Model\Base\DataUnit\DataOperate {
		//
		if( ! ( $this->_dataOperate_Data_Runtime[ $propertyName ] ?? null ) instanceof com\Model\Base\DataUnit\DataOperate ){
			$this->_dataOperate_Data_Runtime[ $propertyName ] = $this->_newDataOperate( $propertyName, $assignDefaultValue, $dataOperateClass );
		}
		// 读取属性值
		return $this->_dataOperate_Data_Runtime[ $propertyName ];
	}

	/**
	 * @param string $propertyName
	 * @param mixed $assignDefaultValue 指定的默认值。[null][默认]
	 * @param string|null $dataOperateClass 自定义类
	 * @return com\Model\Base\DataUnit\DataOperate
	 * @throws
	 */
	protected function _newDataOperate( string $propertyName, mixed $assignDefaultValue = null, string|null $dataOperateClass = null ):com\Model\Base\DataUnit\DataOperate {
		//
		$this->_dataOperate_CheckInit();
		//
		if( ! array_key_exists( $propertyName, $this->_dataOperate_Data ) ){
			throw com\Lib\Err\Exception::makeOfNew( '字段不存在：' . $propertyName, com\Lib\Err\Code::$sysDataNotExist );
		}
		//
		if( $dataOperateClass === null ){
			$dataOperate = new com\Model\Base\DataUnit\DataOperate( $this, $propertyName );
		} else{
			$dataOperate = new $dataOperateClass( $this, $propertyName );
		}
		// 设置默认值
		$dataOperate->setDefaultValue( $assignDefaultValue );
		//
		return $dataOperate;
	}

	/**
	 * @return com\Model\Base\DataUnit\DataOperates
	 */
	public function goDataset():com\Model\Base\DataUnit\DataOperates {
		if( ! isset( $this->_datas ) ){
			//
			$this->_dataOperate_CheckInit();
			//
			$this->_datas = new com\Model\Base\DataUnit\DataOperates( $this, $this->_dataOperate_Data );
		}
		//
		return $this->_datas;
	}

	/**
	 * 初始化检查
	 * @return void
	 */
	private function _dataOperate_CheckInit():void {
		if( is_null( $this->_dataOperate_Data_Runtime ) ){
			$this->_dataOperate_Reset();
		}
	}

	/**
	 * 重置为原始数据
	 * @param string|null $propertyName 指定需要重置的数据名 [null]重置所有
	 * @return void
	 */
	public function _dataOperate_Reset( string|null $propertyName = null ):void {
		if( $propertyName === null ){
			$this->_dataOperate_Data_Runtime = $this->_dataOperate_Data;
		} else{
			$this->_dataOperate_Data_Runtime[ $propertyName ] = $this->_dataOperate_Data[ $propertyName ];
		}
	}

}
